
#!/bin/bash

# 配置文件路径
CONFIG_FILE="/etc/packet_capture.ini"
MIN_VLAN=1
MAX_VLAN=4094
BASE_IP="132.17"

# 定义关联数组存储配置
declare -A config

check_config ()
{
	# 确保配置文件存在
	if [ ! -f "$CONFIG_FILE" ]; then
		echo "错误: 配置文件 $CONFIG_FILE 不存在" >&2
		exit 1
	fi
	echo "开始解析配置文件：$CONFIG_FILE"
    # 逐行解析配置文件
    while IFS= read -r line; do
        # 跳过空行和注释
        if [[ -z "$line" || "$line" == \#* ]]; then
            continue
        fi

        # 同时处理 key=value 和 key:value 格式
        if [[ "$line" =~ ^([^=:#][^=:#]*)[=:](.*)$ ]]; then
            key="${BASH_REMATCH[1]}"
            value="${BASH_REMATCH[2]}"
            # 去除前后空格
            key="$(echo "$key" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
            value="$(echo "$value" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
            config["$key"]="$value"
        fi
        echo "${key}=\"${value}\""
        eval "${key}=\"${value}\""
    done < "$CONFIG_FILE"

    # 验证必需的配置项
    local required_configs=("INTERFACE" "START_VLAN" "END_VLAN" "IMAGE")
    for config in "${required_configs[@]}"; do
        if [ -z "${config}" ]; then
            echo "ERROR" "需要配置项 [$config]。"
            exit 1
        fi
    done
    #验证开始lan和结束lan
    # 检查是否为纯整数
    if ! [[ "${START_VLAN}" =~ ^[0-9]+$ ]]; then
        echo "错误: start_vlan (${START_VLAN}) 不是有效的整数" >&2
        exit 1
    fi
    if ! [[ "${END_VLAN}" =~ ^[0-9]+$ ]]; then
        echo "错误: end_vlan (${END_VLAN}) 不是有效的整数" >&2
        exit 1
    fi
    # 验证 start_vlan <= end_vlan
    if [ "$START_VLAN" -gt "$END_VLAN" ]; then
        echo "错误: start_vlan ($START_VLAN) 不能大于 end_vlan ($END_VLAN)" >&2
        exit 1
    fi

    # 检查是否在合法范围内
    if [ "$END_VLAN" -lt "$MIN_VLAN" ] || [ "$END_VLAN" -gt "$MAX_VLAN" ]; then
        echo "错误: end_vlan ($END_VLAN) 不在合法 VLAN ID 范围 ($MIN_VLAN-$MAX_VLAN) 内" >&2
        exit 1
    fi

    # 查看interface是否存在
    if [ ! -d "/sys/class/net/$INTERFACE" ]; then
        echo "错误: interface ($INTERFACE) 不存在"
		exit 1
    fi
	
	echo "解析配置文件完成"
    # 输出解析结果
    echo "解析结果:"
    for key in "${!config[@]}"; do
        echo "$key: ${config[$key]}"
    done
	echo ""
} # Endf check_config

#检查并创建vlan网卡
check_add_vlan_interface()
{
	if [[ -z $1 ]]; then
		echo "No set vlanid"
		return
	fi
    local vlanid=$1
    local vlan_iface=${INTERFACE}.${vlanid}
	echo "检测并创建vlan网卡${vlan_iface}"
     if [ ! -d "/sys/class/net/$vlan_iface" ]; then
        echo "vlan 网卡($vlan_iface) 不存在， 开始添加"
        echo "ip link add link ${INTERFACE} name ${vlan_iface} type vlan id ${vlanid}"
        ip link add link ${INTERFACE} name ${vlan_iface} type vlan id ${vlanid}
    fi
	echo "ip link set ${vlan_iface} promisc on"
    ip link set ${vlan_iface} promisc on

	echo "ip link set ${vlan_iface} up"
    ip link set ${vlan_iface} up
}
#删除已创建的vlan网卡
check_delete_vlan_interface()
{
	if [[ -z $1 ]]; then
		echo "No set vlanid"
		return
	fi
	local vlanid=$1
    local vlan_iface=${INTERFACE}.${vlanid}
	echo "check and delete vlan interface [${vlan_iface}]"
	if [ -d "/sys/class/net/$vlan_iface" ]; then
		echo "ip link set ${vlan_iface} down"
		ip link set ${vlan_iface} down
		echo "ip link delete ${vlan_iface}"
		ip link delete ${vlan_iface}
	fi
}

#创建docker macvlan 网卡
docker_macvlan_network_create()
{
	if [[ -z $1 ]]; then
		echo "No set vlanid"
		return
	fi
    local vlanid=$1
    local vlan_iface=${INTERFACE}.${vlanid}
    local macvlan_iface=vlan${vlanid}

    # 计算第三个和第四个八位字节
    local third_octet=$(( (vlan_id - START_VLAN) / 128 ))
    local fourth_octet=$((( (vlan_id - START_VLAN) % 128 ) * 2 ))
	if [[ ! -z ${SUBNET_BASEIP12} ]]; then
		BASE_IP=${SUBNET_BASEIP12}
	fi
    # 构建并输出子网信息
    local subnet="${BASE_IP}.${third_octet}.${fourth_octet}/31"
    local gateway="${BASE_IP}.${third_octet}.${fourth_octet}"
	echo "计算第三个和第四个八位字节, 组合成subnet IP, 创建docker macvlan 网络"
    echo "subnet:${subnet}"
    echo "gateway:${gateway}"
    echo "docker network cread -d macvlan -o parent=${vlan_iface} -o macvlan_mode=passthru --subnet=${subnet} ${macvlan_iface}"
    docker network cread -d macvlan -o parent=${vlan_iface} -o macvlan_mode=passthru --subnet=${subnet} ${macvlan_iface}
}

#删除docker macvlan 网卡
docker_macvlan_network_delete()
{
	if [[ -z $1 ]]; then
		echo "No set vlanid"
		return
	fi
    local vlanid=$1
    local macvlan_iface=vlan${vlanid}
    local container_name=${macvlan_iface}
	echo "docker network disconnect ${macvlan_iface} ${container_name}"
	docker network disconnect ${macvlan_iface} ${container_name}

	echo "docker network rm ${macvlan_iface}"
	docker network rm ${macvlan_iface}
}

#创建运行docker容器，设置vlan网络为eth0用于抓包
#连接bridge网络作为eth1用于连接服务器
docker_container_run()
{
	if [[ -z $1 ]]; then
		echo "No set vlanid"
		return
	fi
    local vlanid=$1
    local macvlan_iface=vlan${vlanid}
    local container_name=${macvlan_iface}
	echo "运行docker 设定挂载信息、应用macvlan 网络用于抓包"
    mount_op="-v /etc/localtime:/etc/localtime:ro -v /etc/timezone:/etc/timezone:ro -v ${SAVE_PATH}:/pcapcap_files"
    echo "docker run ${mount_op} --net=${macvlan_iface} --cap-add=NET_RAW --cap-add=NET_ADMIN --name=${container_name} -d ${DOCKER_IMAGE} /usr/sbin/docker_run_always.sh"
    docker run ${mount_op} --net=${macvlan_iface} --cap-add=NET_RAW --cap-add=NET_ADMIN --name=${container_name} -d ${DOCKER_IMAGE} /usr/sbin/docker_run_always.sh

	echo "连接docker容器与bridge网络,用于网络连接和数据交互"
    echo "docker network connect bridge ${container_name}"
    docker network connect bridge ${container_name}

	echo "设置docker容器运行业务程序"
    echo "docker exec -d ${container_name} packet_capture --pcap_dev=eth0 --vlanid=${vlanid} --host=${MQTT_HOST} --topic=/pkgcap/${vlanid}/ToManager --subtopic=/pkgcap/${vlanid}/ToCapture --username ${MQTT_USERNAME} --password ${MQTT_USERPWD} --log_conf=/etc/packet_capture_log.cfg --daemon"
    docker exec -d ${container_name} packet_capture --pcap_dev=eth0 --vlanid=${vlanid} --host=${MQTT_HOST} --topic=/pkgcap/${vlanid}/ToManager --subtopic=/pkgcap/${vlanid}/ToCapture --username ${MQTT_USERNAME} --password ${MQTT_USERPWD} --log_conf=/etc/packet_capture_log.cfg --daemon
}

#关闭并删除docker容器
docker_container_stop()
{
	if [[ -z $1 ]]; then
		echo "No set vlanid"
		return
	fi
    local vlanid=$1
    local container_name=vlan${vlanid}
	echo "docker stop "$container_name" >/dev/null 2>&1"
	docker stop "$container_name" >/dev/null 2>&1

	echo "docker rm "$container_name" >/dev/null 2>&1"
	docker rm "$container_name" >/dev/null 2>&1
}

# 查看状态 包含vlan网卡、macvlan网卡、docker容器的运行状态
state_check()
{
	if [[ -z $1 ]]; then
		echo "No set vlanid"
		return
	fi
    local vlanid=$1
    local vlan_iface=${INTERFACE}.${vlanid}
    local macvlan_iface=vlan${vlanid}
    local container_name=${macvlan_iface}
	local vlan_iface_state
	if [ -d "/sys/class/net/$vlan_iface" ]; then
		vlan_iface_state=1
	else
		vlan_iface_state=0
	fi
	local macvlan_state="$(docker network ls |grep "$macvlan_iface" |wc -l)"
	local docker_ps_state="$(docker ps -a |grep "$container_name" |wc -l)"
	
	printf "|%6s|%11s|%5s|%10s|%5s|%10s|%5s|\n" "$vlanid" "$vlan_iface" "$vlan_iface_state" "$macvlan_iface" "$macvlan_state" "$container_name" "$docker_ps_state"
}

main () {
	local cmd=$1
	local start_vlan=$2
	local end_vlan=$3

    case "$cmd" in
    start)
		#读取配置文件
		check_config
		if [[ -z $start_vlan ]] || [[ $start_vlan -lt ${START_VLAN} ]]; then
			start_vlan=${START_VLAN}
		fi
		if [[ -z $end_vlan ]] || [[ $end_vlan -gt ${END_VLAN} ]]; then
			end_vlan=${END_VLAN}
		fi
		echo "CMD:$cmd"
		echo ""

		vlan_id=${start_vlan}
		while [ $vlan_id -le $end_vlan ]; do
			check_add_vlan_interface ${vlan_id}
			echo ""
			docker_macvlan_network_create ${vlan_id}
			echo ""
			docker_container_run ${vlan_id}
			echo ""
			echo ""
			vlan_id=$((vlan_id + 1))
		done
    ;;
    stop)
		#读取配置文件
		check_config
		if [[ -z $start_vlan ]] || [[ $start_vlan -lt ${START_VLAN} ]]; then
			start_vlan=${START_VLAN}
		fi
		if [[ -z $end_vlan ]] || [[ $end_vlan -gt ${END_VLAN} ]]; then
			end_vlan=${END_VLAN}
		fi
		echo "CMD:$cmd"
		echo ""

		vlan_id=${start_vlan}
		while [ $vlan_id -le $end_vlan ]; do
			docker_container_stop ${vlan_id}
			echo ""
			docker_macvlan_network_delete ${vlan_id}
			echo ""
			check_delete_vlan_interface ${vlan_id}
			echo ""
			echo ""
			vlan_id=$((vlan_id + 1))
		done
    ;;
    state)
		#读取配置文件
		check_config
		if [[ -z $start_vlan ]] || [[ $start_vlan -lt ${START_VLAN} ]]; then
			start_vlan=${START_VLAN}
		fi
		if [[ -z $end_vlan ]] || [[ $end_vlan -gt ${END_VLAN} ]]; then
			end_vlan=${END_VLAN}
		fi
		echo "CMD:$cmd"
		echo ""
		vlan_id=${start_vlan}
		# |vlanid|interface|state|macvlan|state|container|state|
		printf "|%6s|%11s|%5s|%10s|%5s|%10s|%5s|\n" "VLANID" "INTERFACE" "STATE" "MACVLAN" "STATE" "CONTAINER" "STATE"
		while [ $vlan_id -le $end_vlan ]; do
			state_check ${vlan_id}
			vlan_id=$((vlan_id + 1))
		done
    ;;
    *)
		help_func
    ;;
    esac
}

help_func() {
	echo ""
	echo "运行 $0 添加命令参数 支持 start/stop/state ,后面可以选使用start_vlan 与 end_vlan来部分打开"
	echo "   commond:"
	echo "          start - 创建网络环境并开始执行"
	echo "           stop - 结束执行并清理环境"
	echo "           state - 查看网络环境和运行状态"
	echo "start_vlan：可选,纯数字,开始的vlan编号,与end_vlan配合使用"
	echo "  sop_vlan：可选,纯数字,结束的vlan编号,与start_vlan配合使用,不小于start_vlan"
	echo "默认配置文件：$CONFIG_FILE"
	echo "运行实例："
	echo "       $0 start"
	echo "       $0 start 3001 3010"
	echo "       $0 stop"
	echo "       $0 stop 3001 3010"
	echo ""
}

if [[ $# -eq 1 ]] || [[ $# -eq 3 ]]; then
	main "$1" "$2" "$3"
else
	help_func
fi
